﻿using System;
using System.Collections.Generic;
using System.IO;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.DataSourcesFile;
using ESRI.ArcGIS.DataSourcesRaster;
using ESRI.ArcGIS.GeoAnalyst;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;

namespace ODM_Code.Code
{
    public class CreateBasemapCode
    {
        private esriUtil.rasterUtil eru;
        public Dictionary<string, LayerData> layerInfoDict;

        private IFeatureClass projectMaskFeatureClass;
        private IFeatureClass treatmentFeatureClass;
        private IRaster treatgridRaster;
        private IRaster aspectRaster;
        private IRaster elevationRaster;
        private IRaster slopeRaster;

        string exportLocation;

        public CreateBasemapCode(string pathToNewProjectInput)
        {
            eru = new esriUtil.rasterUtil();
            layerInfoDict = new Dictionary<string, LayerData>();
            exportLocation = pathToNewProjectInput;
        }

        public void LoadAllTheLayers()
        {
            string path;
            this.projectMaskFeatureClass = this.LoadLayer("maskLayer");
            this.treatmentFeatureClass = this.LoadLayer("treatLayer");
            path = layerInfoDict["aspect"].fullPath;
            this.aspectRaster = eru.returnRaster(path);
            path = layerInfoDict["elevation"].fullPath;
            this.elevationRaster = eru.returnRaster(path);
            path = layerInfoDict["slope"].fullPath;
            this.slopeRaster = eru.returnRaster(path);
            path = layerInfoDict["treatgrid"].fullPath;
            this.treatgridRaster = eru.returnRaster(path);
        }

        private IFeatureClass LoadLayer(string key)
        {
            string path = layerInfoDict[key].fullPath;
            string wPath = path.Substring(0, path.LastIndexOf('\\'));
            string name = layerInfoDict[key].name;
            IWorkspaceFactory wkFact = new ShapefileWorkspaceFactoryClass();
            IFeatureWorkspace wks = (IFeatureWorkspace)(wkFact.OpenFromFile(wPath, 0));
            IFeatureClass fc = wks.OpenFeatureClass(name);
            return fc;
        }

        public void ProcessData()
        {
            this.ClipFeatures();
            this.UpdateAcresInFeature();

            //treatgridRaster = (IRaster)this.RasterizeTreat(treatmentFeatureClass, exportLocation, 0);
            treatgridRaster = this.ClipRasters(treatgridRaster);
            aspectRaster = this.ClipRasters(aspectRaster);
            elevationRaster = this.ClipRasters(elevationRaster);
            slopeRaster = this.ClipRasters(slopeRaster);

            this.SaveHelper(treatgridRaster, "treatgrid");
            this.SaveHelper(aspectRaster, "aspect");
            this.SaveHelper(elevationRaster, "elevation");
            this.SaveHelper(slopeRaster, "slope");

            treatgridRaster = eru.returnRaster(exportLocation + "\\treatgrid.img");
            aspectRaster = eru.returnRaster(exportLocation + "\\aspect.img");
            elevationRaster = eru.returnRaster(exportLocation + "\\elevation.img");
            slopeRaster = eru.returnRaster(exportLocation + "\\slope.img");

            this.DumpToASCII(treatgridRaster, "treatgrid");
            this.DumpToASCII(aspectRaster, "aspect");
            this.DumpToASCII(elevationRaster, "elevation");
            this.DumpToASCII(slopeRaster, "slope");
        }

        private void ClipFeatures()
        {
            ITable inputTable = (ITable)treatmentFeatureClass;
            ITable clipTable = (ITable)projectMaskFeatureClass;
            IFeatureClassName outputName = new FeatureClassNameClass();
            outputName.FeatureType = esriFeatureType.esriFTSimple;
            outputName.ShapeFieldName = "Shape";
            outputName.ShapeType = treatmentFeatureClass.ShapeType;

            IWorkspaceName newWName = new WorkspaceNameClass();
            newWName.WorkspaceFactoryProgID = "esriCore.ShapeFileWorkspaceFactory.1";
            newWName.PathName = exportLocation;

            IDatasetName dsName = (IDatasetName)outputName;
            dsName.Name = "treat";
            dsName.WorkspaceName = newWName;

            IBasicGeoprocessor gp = new BasicGeoprocessorClass();
            try
            {
                IFeatureClass clippedFeature = gp.Clip(inputTable, false, clipTable, false, 0.0, outputName);
                treatmentFeatureClass = clippedFeature;

                IFeatureLayer fLayer = new FeatureLayerClass();
                fLayer.FeatureClass = clippedFeature;
                ILayer pLayer = (ILayer)fLayer;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Trace.WriteLine(ex.Message);
                //throw;
            }
        }

        private void UpdateAcresInFeature()
        {
        }

        private IGeoDataset RasterizeTreat(IFeatureClass feaureClass, String string_RasterWorkspace, Int32 int32_NumberOfCells)
        {
            IGeoDataset geoDataset = (IGeoDataset)feaureClass; // Explicit Cast
            ISpatialReference spatialReference = geoDataset.SpatialReference;

            // Create a RasterMaker operator
            IConversionOp conversionOp = new RasterConversionOpClass();

            IWorkspaceFactory workspaceFactory = new RasterWorkspaceFactoryClass();

            // set output workspace
            IWorkspace workspace = workspaceFactory.OpenFromFile(string_RasterWorkspace, 0);

            // Create analysis environment
            IRasterAnalysisEnvironment rasterAnalysisEnvironment = (ESRI.ArcGIS.GeoAnalyst.IRasterAnalysisEnvironment)conversionOp; // Explicit Cast
            rasterAnalysisEnvironment.OutWorkspace = workspace;

            IEnvelope envelope = new EnvelopeClass();
            envelope = geoDataset.Extent;

            // Set cell size
            Double double_xMin = envelope.XMin;
            Double double_xMax = envelope.XMax;
            Double double_difference = double_xMax - double_xMin;
            Double double_cellSize = double_difference / int32_NumberOfCells;
            object object_cellSize = (System.Object)double_cellSize;
            rasterAnalysisEnvironment.SetCellSize(esriRasterEnvSettingEnum.esriRasterEnvValue, ref object_cellSize);

            // Set output extent
            object object_Envelope = (System.Object)envelope; // Explict Cast
            object object_Missing = System.Type.Missing;
            rasterAnalysisEnvironment.SetExtent(esriRasterEnvSettingEnum.esriRasterEnvValue, ref object_Envelope, ref object_Missing);

            // Set output spatial reference
            rasterAnalysisEnvironment.OutSpatialReference = spatialReference;

            // Perform spatial operation
            IRasterDataset rasterDataset = new RasterDatasetClass();

            // Create the new raster name that meets the coverage naming convention
            String string_RasterName = feaureClass.AliasName;
            if (string_RasterName.Length > 13)
            {
                string_RasterName = string_RasterName.Substring(0, 13);
            }
            string_RasterName = string_RasterName.Replace(" ", "_");
            rasterDataset = conversionOp.ToRasterDataset(geoDataset, "GRID", workspace, string_RasterName);
            IGeoDataset geoDataset_output = (IGeoDataset)rasterDataset;

            return geoDataset_output;
        }

        private IRaster ClipRasters(IRaster rasterToClip)
        {
            IFeature feat = projectMaskFeatureClass.GetFeature(0);
            IGeometry geom = feat.Shape.Envelope;
            return eru.clipRasterFunction(rasterToClip, geom, esriRasterClippingType.esriRasterClippingOutside);
        }

        private void SaveHelper(IRaster rasterToSave, string name)
        {
            IWorkspaceFactory wkFact = new RasterWorkspaceFactoryClass();
            IWorkspace wks = wkFact.OpenFromFile(exportLocation, 0);
            IRasterDataset saveRas = eru.saveRasterToDataset(rasterToSave, name, wks, esriUtil.rasterUtil.rasterType.IMAGINE);
        }

        private void DumpToASCII(IRaster rasterToExport, string name)
        {
            IRasterProps rp = (IRasterProps)rasterToExport;
            int ncols = rp.Width;
            int nrows = rp.Height;
            double xllcorner = rp.Extent.LowerLeft.X;
            double yllcorner = rp.Extent.LowerLeft.Y;
            IPnt pntCellsize = rp.MeanCellSize();
            object cellsize = pntCellsize.X;

            System.Array nodataary = (System.Array)rp.NoDataValue;
            object nodataval = nodataary.GetValue(0);

            rstPixelType pixelType = rp.PixelType;

            string filename = exportLocation + "\\" + name + ".txt";
            StreamWriter sw = new StreamWriter(filename);

            sw.WriteLine("ncols         " + ncols.ToString());
            sw.WriteLine("nrows         " + nrows.ToString());
            sw.WriteLine("xllcorner     " + xllcorner.ToString());
            sw.WriteLine("yllcorner     " + yllcorner.ToString());
            sw.WriteLine("cellsize      " + cellsize.ToString());
            //sw.WriteLine("NODATA_value  " + nodataval.ToString());
            sw.WriteLine("NODATA_value  " + "-9999");

            IRaster2 zRaster = (IRaster2)rasterToExport;
            IPnt pnt = new PntClass();
            pnt.SetCoords((double)ncols, (double)nrows);
            IRasterCursor zCursor = zRaster.CreateCursorEx(pnt);
            IRasterBandCollection zBands = (IRasterBandCollection)zRaster.RasterDataset;
            IPixelBlock3 zPB3 = null;

            long blockwidth = 0;
            long blockheight = 0;
            System.Array zPixels = null;

            object z;

            do
            {
                zPB3 = (IPixelBlock3)zCursor.PixelBlock;
                blockwidth = zPB3.Width;
                blockheight = zPB3.Height;
                //zPB3.Mask(rp.NoDataValue);

                zPixels = (System.Array)zPB3.get_PixelData(0);

                for (long i = 0; i < blockheight; i++)
                {
                    for (long j = 0; j < blockwidth; j++)
                    {
                        z = zPixels.GetValue(j, i);

                        if (Convert.ToDouble(z) == Convert.ToDouble(nodataval))
                        {
                            z = -9999;
                        }

                        //switch (pixelType)
                        //{
                        //    case rstPixelType.PT_DOUBLE:
                        //        break;
                        //    case rstPixelType.PT_FLOAT:
                        //        break;
                        //    case rstPixelType.PT_LONG:
                        //        break;
                        //    case rstPixelType.PT_SHORT:
                        //        break;
                        //}

                        sw.Write(z.ToString() + " ");
                    }

                    sw.Write("\n");
                }

            } while (zCursor.Next() == true);

            sw.Close();
        }


        public class LayerData
        {
            public string fullPath { get; set; }
            public string name { get; set; }
            public LayerData(string fullPath, string name)
            {
                this.fullPath = fullPath;
                this.name = name;
            }
        }
    }
}
